package com.edu.juc.interrupt.producerConsumer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumerExample {
    // 共享资源，这里以一个简单的整数表示任务数量
    private int taskCount = 0;
    private final int capacity = 5; // 缓冲区容量

    // 创建锁和条件变量
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();  // 条件：缓冲区未满
    private final Condition notEmpty = lock.newCondition(); // 条件：缓冲区非空

    // 生产者方法
    public void produce() throws InterruptedException {
        lock.lock(); // 获取锁
        try {
            while (taskCount >= capacity) {
                // 如果缓冲区已满，生产者等待"未满"条件
                System.out.println("缓冲区已满，生产者等待...");
                notFull.await(); // 等待的同时会释放锁，被唤醒后会自动重新获取锁
            }
            taskCount++; // 生产一个任务
            System.out.println("生产者生产了一个任务，当前任务数: " + taskCount);
            // 生产后，缓冲区肯定非空了，唤醒一个消费者线程
            notEmpty.signal();
        } finally {
            lock.unlock(); // 最终释放锁
        }
    }

    // 消费者方法
    public void consume() throws InterruptedException {
        lock.lock(); // 获取锁
        try {
            while (taskCount <= 0) {
                // 如果缓冲区为空，消费者等待"非空"条件
                System.out.println("缓冲区为空，消费者等待...");
                notEmpty.await(); // 等待的同时会释放锁，被唤醒后会自动重新获取锁
            }
            taskCount--; // 消费一个任务
            System.out.println("消费者消费了一个任务，当前任务数: " + taskCount);
            // 消费后，缓冲区肯定不满了，唤醒一个生产者线程
            notFull.signal();
        } finally {
            lock.unlock(); // 最终释放锁
        }
    }

    public static void main(String[] args) {
        ProducerConsumerExample example = new ProducerConsumerExample();

        // 创建生产者线程
        Thread producerThread = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    example.produce();
                    Thread.sleep(100); // 模拟生产耗时
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 创建消费者线程
        Thread consumerThread = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    example.consume();
                    Thread.sleep(150); // 模拟消费耗时
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 启动线程
        producerThread.start();
        consumerThread.start();
    }
}
